package arcane.object.game.sprite;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import org.lwjgl.opengl.GL11;

import arcane.object.gui.Border;

import com.golden.gamedev.engine.BaseInput;

public class MenuSprite extends GeometricSprite {
	public static BaseInput bsInput;

	/**
	 * Flag for if mouse is over this menu sprite
	 */
	protected boolean mouseOver;

	/**
	 * Whether this sprite responds to input
	 */
	protected boolean enabled;

	/**
	 * ID used in action events for mouse entering this sprite
	 */
	public static final int MOUSE_ENTERED = 0;

	/**
	 * ID used in action events for mouse exiting this sprite
	 */
	public static final int MOUSE_EXITED = 1;

	/**
	 * ID used in action events for mouse button 1 being pressed on this sprite
	 */
	public static final int MOUSE_DOWN = 2;

	/**
	 * ID used in action events for mouse button 1 being clicked on this sprite
	 */
	public static final int MOUSE_CLICKED = 3;

	/**
	 * ID used in action events implying event's cause is either
	 * inconsequential, or undetermined.
	 */
	public static final int UNSPECIFIED = 4;

	// ActionListeners interested in this sprite. Should really use EventList,
	// but I don't know if it brings additional overhead, so I'm using ArrayList
	private List<ActionListener> listeners;

	// Border for this sprite
	private Border border;
	// This sprite's insets
	protected Insets inset;

	/**
	 * This Sprite's action command used in generating action events
	 */
	protected String command;

	protected boolean focused;

	/**
	 * Constructs a new MenuSprite at a specific location (x,y) with no image
	 * 
	 * @param x
	 *            specified x location
	 * @param y
	 *            specified y location
	 */
	public MenuSprite(int x, int y) {
		this(null, x, y);
	}

	/**
	 * Constructs a new MenuSprite at a specific location (x,y) with a specific
	 * image.
	 * 
	 * @param img
	 *            specified image
	 * @param x
	 *            specified x location
	 * @param y
	 *            specified y location
	 */
	public MenuSprite(BufferedImage img, int x, int y) {
		super(img, x, y);
		enabled = true;
		command = "";
		listeners = new ArrayList<ActionListener>();
		inset = new Insets(0, 0, 0, 0);
	}

	/**
	 * Sets this sprite's action command used in generating action events.
	 * 
	 * @param cmd
	 *            sprite's action command
	 */
	public void setActionCommand(String cmd) {
		command = cmd;
	}

	/**
	 * Returns this MenuSprite's action command assigned to generated
	 * ActionEvents.
	 * 
	 * @return this MenuSprite's ActionCommand
	 */
	public String getActionCommand() {
		return command;
	}

	/**
	 * Sets this MenuSprite's border
	 * 
	 * @param border
	 *            specified border
	 */
	public void setBorder(Border border) {
		this.border = border;
	}

	/**
	 * Returns this MenuSprite's border
	 * 
	 * @return this MenuSprite's border
	 */
	public Border getBorder() {
		return border;
	}

	public void setInsets(Insets inset) {
		this.inset = inset;
	}

	public Insets getInsets() {
		return inset;
	}

	/**
	 * Registers an ActionListener with this MenuSprite. Registered listeners
	 * will receive action commands from MenuSprites.
	 * 
	 * @param listen
	 *            some action listener
	 */
	public void addActionListener(ActionListener listen) {
		listeners.add(listen);
	}

	/**
	 * Returns this MenuSprite's width plus its right inset
	 */
	public int getWidth() {
		return width + inset.right;
	}

	/**
	 * Returns this MenuSprite's height plus its bottom inset
	 */
	public int getHeight() {
		return height + inset.bottom;
	}

	/**
	 * Sets OpenGL rendering color from java.awt.Color object.
	 * 
	 * @param color
	 *            java.awt.Color object
	 */
	public void setOpenGLColor(Color color) {
		setOpenGLColor(color, (float) color.getAlpha() / 255);
	}

	public void setOpenGLColor(Color color, float alpha) {
		GL11.glColor4f((float) color.getRed() / 255,
				(float) color.getGreen() / 255, (float) color.getBlue() / 255,
				alpha);
	}

	public void setFocused(boolean focused) {
		this.focused = focused;
	}

	public boolean hasFocus() {
		return focused;
	}

	/**
	 * Updates this sprite's 2 dimensional motion, and checks for input.
	 */
	public void update(long time) {
		super.update(time);
		if (enabled && isActive()) {
			int mx = bsInput.getMouseX();
			int my = bsInput.getMouseY();
			if (this.getBounds().contains(mx, my)) {
				if (!mouseOver)
					mouseEntered(mx, my);
				mouseOver = true;
			} else if (mouseOver) {
				mouseOver = false;
				mouseExited(mx, my);
			}
			if (mouseOver && bsInput.isMouseDown(MouseEvent.BUTTON1)) {
				mouseDown(mx, my);
			}
			if (mouseOver && bsInput.isMousePressed(MouseEvent.BUTTON1)) {
				mouseClicked(mx, my);
			}
		}
	}

	public void render(Graphics2D g, int x, int y) {
		super.render(g, x, y);
		if (border != null)
			border.paintBorder(this, g);
	}

	/**
	 * Sets whether this sprite checks for input
	 * 
	 * @param enabled
	 *            whether sprite checks for input.
	 */
	public void setEnabled(boolean enabled) {
		this.enabled = enabled;
	}

	/**
	 * Returns whether this sprite checks for input.
	 * 
	 * @return whether this sprite checks for input.
	 */
	public boolean isEnabled() {
		return enabled;
	}

	/**
	 * Sends a specified ActionEvent to listeners registered with this
	 * MenuSprite
	 * 
	 * @param e
	 *            specified ActionEvent
	 */
	protected void fireEvent(ActionEvent e) {
		if (enabled) {
			for (int i = 0; i < listeners.size(); i++) {
				listeners.get(i).actionPerformed(e);
			}
		}
	}

	/**
	 * Called when mouse button 1is down over this MenuSprite. Fires an
	 * ActionEvent to all registered components indicating this.
	 * 
	 * @param x
	 *            x location of mouse
	 * @param y
	 *            y location of mouse
	 */
	public void mouseDown(int x, int y) {
		fireEvent(new ActionEvent(this, MOUSE_DOWN, command));
	}

	/**
	 * Called when mouse has exited this MenuSprite. Fires an ActionEvent to all
	 * registered components indicating this.
	 * 
	 * @param x
	 *            x location immediately after exiting
	 * @param y
	 *            y location immediately after exiting
	 */
	public void mouseExited(int x, int y) {
		fireEvent(new ActionEvent(this, MOUSE_EXITED, command));
	}

	/**
	 * Called when mouse has clicked button 1 on this MenuSprite. Fires an
	 * ActionEvent to all registered components indicating this.
	 * 
	 * @param x
	 *            x location of mouse after mouse click
	 * @param y
	 *            y location of mouse after mouse click
	 */
	public void mouseClicked(int x, int y) {
		fireEvent(new ActionEvent(this, MOUSE_CLICKED, command));
	}

	/**
	 * Called when mouse has entered this sprite. Fires an ActionEvent to all
	 * registered components indicating this.
	 * 
	 * @param x
	 *            x location of mouse after entering sprite
	 * @param y
	 *            y location of mouse after entering sprite
	 */
	public void mouseEntered(int x, int y) {
		fireEvent(new ActionEvent(this, MOUSE_ENTERED, command));
	}
}